package com.gopay.bis.icbc.bcdl.operation;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import javax.xml.crypto.dsig.TransformException;

import org.apache.commons.lang.StringUtils;
import org.apache.xmlbeans.XmlException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.infosec.util.Base64;

import com.gopay.bis.common.util.TransUtil;
import com.gopay.bis.common.util.constants.Constants4BankSwitch;
import com.gopay.common.constants.bank.IcbcConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.icbc.bcdl.pay.IcbcMessageData;
import com.gopay.common.domain.bank.icbc.bcdl.query.balance.req.CMSReq;
import com.gopay.common.domain.bank.icbc.bcdl.query.balance.req.EbReq;
import com.gopay.common.domain.bank.icbc.bcdl.query.balance.req.InReq;
import com.gopay.common.domain.bank.icbc.bcdl.query.balance.req.PubReq;
import com.gopay.common.domain.bank.icbc.bcdl.query.balance.req.RdReq;
import com.gopay.common.domain.bank.icbc.bcdl.query.balance.res.CMSRes;
import com.gopay.common.exception.GopayException;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class QueryBalformer {
	
	/** Logger for logging information. */
	protected Logger log = LoggerFactory.getLogger(this.getClass());
	
	/** new Initiate capacity. */
	private static final int INIT_CAPACITY = 10;
	
	protected static final String SUC = "0";
	
	/** 交易代码. */
	protected String transCode = null;
	/** 集团CIS号. */
	protected String cis = null;
	/** 归属银行编号. */
	protected String bankCode = null;
	/** 证书ID. */
	protected String id = null;
	/** 商城账号. */
	protected String shopAcct = null;
	/** 版本号. */
	protected String version = null;
	
	public Object format(Object sendMsgData,String id) throws GopayException {
		return doFormat((IcbcMessageData) sendMsgData,id);
	}
	
	/**
	 * Parse message.
	 * 
	 * @param receivedMsgData
	 *            应答报文.
	 * @return IcbcMessageData 工行数据结构体.
	 * @throws TransformException
	 *             报文格式错误.
	 */
	public Object parse(Object receivedMsgData) throws GopayException {
		String msg = (String) receivedMsgData;
		
		try {
			msg = new String(msg.getBytes("UTF-8"), "GBK");

			String plainMsg = "";
			plainMsg = new String(Base64.decode(msg),"GBK");
			log.info("ICBC QueryBalf Receive XmlString: \n"
					+ plainMsg);
			String returnCode = TransUtil.getMsgField(
					IcbcConstants.RETURN_CODE_BEGIN_TAG_NEW,
					IcbcConstants.RETURN_CODE_END_TAG_NEW, plainMsg);
			if (SUC.equals(returnCode)) {
				return doParse(plainMsg);
			} else {
				IcbcMessageData tranMsg = new IcbcMessageData();
				String returnMsg = TransUtil.getMsgField(
						IcbcConstants.RETURN_MSG_BEGIN_TAG_NEW,
						IcbcConstants.RETURN_MSG_END_TAG_NEW, plainMsg);
				tranMsg.setRetCode(StringUtils.isEmpty(returnCode) ? Constants4BankSwitch.DEFAULT_RETURN_CODE
						: returnCode);
				tranMsg.setErrMsg(StringUtils.isEmpty(returnMsg) ? Constants4BankSwitch.DEFAULT_RETURN_MSG
						: returnMsg);
				return tranMsg;
				
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6052);
		} catch (XmlException e) {
			e.printStackTrace();
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6052);
		}
	}
	
	protected Object doParse(String msg) throws XmlException {
			log.info("ICBC QueryBalf receive Message: \n" + msg.toString());
			CMSRes cms = new CMSRes();
			
			String respStr = msg.substring(msg.indexOf("?>") + 2);
			XStream xs = new XStream(new DomDriver());
			xs.autodetectAnnotations(true);
			xs.toXML(cms);
			cms = (CMSRes) xs.fromXML(respStr);
			
			IcbcMessageData tranMsg = new IcbcMessageData();
		tranMsg.setOutStlmCd("ICBC");
			tranMsg.setTransCode(cms.getEb().getPub().getTransCode());
			tranMsg.setCis(cms.getEb().getPub().getCis());
			tranMsg.setBankCode(cms.getEb().getPub().getBankCode());
			tranMsg.setId(cms.getEb().getPub().getId());
			tranMsg.setTranDate(cms.getEb().getPub().getTranDate());
			tranMsg.setTranTime(cms.getEb().getPub().getTranTime());
			tranMsg.setfSeqno(cms.getEb().getPub().getfSeqno());
			tranMsg.setRetCode(cms.getEb().getPub().getRetCode());
			tranMsg.setRetMsg(cms.getEb().getPub().getRetMsg());
			tranMsg.setResult(tranMsg.getRetCode());
			if (cms.getEb().getOut().getRd() == null) {
				tranMsg.setResult(IcbcConstants.NCPAYENT_STATUS_NO_FOUND);
				return tranMsg;
			}
			tranMsg.setISeqno(cms.getEb().getOut().getRd().getiSeqno());
			tranMsg.setPayAccNo(cms.getEb().getOut().getRd().getAccNo());
			tranMsg.setCurrType(cms.getEb().getOut().getRd().getCurrType());
			tranMsg.setAcctProperty(cms.getEb().getOut().getRd().getAcctProperty());
			tranMsg.setAccBalance(cms.getEb().getOut().getRd().getAccBalance());
			tranMsg.setBalance(cms.getEb().getOut().getRd().getBalance());
			
			BigDecimal ONEHUNDRED = new BigDecimal(100);
            BigDecimal originalAmount = new BigDecimal(cms.getEb().getOut().getRd().getUsableBalance());
			tranMsg.setUsableBalance(originalAmount.divide(ONEHUNDRED).toString());
			tranMsg.setFrzAmt(cms.getEb().getOut().getRd().getFrzAmt());
			tranMsg.setQueryTime(cms.getEb().getOut().getRd().getQueryTime());
			tranMsg.setIRetCode(cms.getEb().getOut().getRd().getiRetCode());
			tranMsg.setIRetMsg(cms.getEb().getOut().getRd().getiRetMsg());
			tranMsg.setRepReserved3(cms.getEb().getOut().getRd().getRepReserved3());
			tranMsg.setAccName(cms.getEb().getOut().getRd().getAccName());
			tranMsg.setHoldAmt(cms.getEb().getOut().getRd().getHoldAmt());
			tranMsg.setLastIntrDate(cms.getEb().getOut().getRd().getLastIntrDate());
			tranMsg.setLastTranDate(cms.getEb().getOut().getRd().getLastTranDate());
			tranMsg.setInterDeposit(cms.getEb().getOut().getRd().getInterDeposit());
			tranMsg.setInterWithdrawal(cms.getEb().getOut().getRd().getInterWithdrawal());
			tranMsg.setAcctSeq(cms.getEb().getOut().getRd().getAcctSeq());
			
			return tranMsg;
	}
	public Object doFormat(IcbcMessageData msg,String id) throws GopayException {
		try{
			
			msg.setTransCode(this.transCode);
			msg.setCis(this.cis);
			msg.setBankCode(this.bankCode);
			msg.setId(id);
			msg.setVersion(this.version);

			PubReq pub = new PubReq();
			pub.setTransCode(this.transCode);
			pub.setCis(this.cis);
			pub.setBankCode(this.bankCode);
			pub.setId(msg.getId());
			pub.setTranDate(msg.getTranDate());
			pub.setTranTime(msg.getTranTime());
			pub.setfSeqno(msg.getfSeqno());
			
			RdReq rd = new RdReq();
			rd.setiSeqno(msg.getfSeqno());
			rd.setAccNo(this.shopAcct);
			rd.setCurrType(msg.getCurrType());
			rd.setReqReserved3(msg.getReqReserved3());
			rd.setAcctSeq(msg.getAcctSeq());
			
			InReq in = new InReq();
			in.setTotalNum("1");
			in.setBLFlag(msg.getBlFlag());
			in.setSynFlag(msg.getSynFlag());
			in.setRd(rd);
			
			EbReq eb = new EbReq();
			eb.setPub(pub);
			eb.setIn(in);
			
			CMSReq cms = new CMSReq();
			cms.setEb(eb);
			
			XStream xstream = new XStream();
			xstream.autodetectAnnotations(true);
			xstream.processAnnotations(CMSReq.class);
			String cmsString= xstream.toXML(cms);
			StringBuffer xmlString = new StringBuffer("<?xml version=\"1.0\" encoding=\"GBK\" ?>\n");
			xmlString.append(cmsString);
			log.info("Message to be sent: \n" + xmlString.toString());
			return xmlString.toString().getBytes("UTF-8");
		}catch(Exception e){
			e.printStackTrace();
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6050);
		}
	}
	
	/**
	 * 取得发送NetSafeClient的请求参数.
	 * 
	 * @param obj
	 *            报文.
	 * @param formatRes
	 *            format res.
	 * @return map.
	 */
	public Map getIssueNCParaMap(Object obj, Object formatRes)throws GopayException {
		byte[] formatResByte = (byte[]) formatRes;
		try {
			formatResByte = new String(formatResByte).getBytes("GBK");
		
		IcbcMessageData msg = (IcbcMessageData) obj;
		String reqData = null;
		reqData = new String(formatResByte);
		
		// 组织提交工行所需form的field域及其值，报文体由IcbcConstants.REQ_DATA指定
		Map requestParaMap = new HashMap(INIT_CAPACITY);
		// 证书ID
		requestParaMap.put(IcbcConstants.USER_ID, msg.getId());
		// 请求时间
		requestParaMap.put(IcbcConstants.SEND_TIME, TransUtil.getSendTime());
		// 版本号（不同版本号对应的接口格式不同，请参考具体交易的接口文档)
		requestParaMap.put(IcbcConstants.VERSION, msg.getVersion());
		// 交易码
		requestParaMap.put(IcbcConstants.TRANS_CODE, msg.getTransCode());
		// 客户的归属单位
		requestParaMap.put(IcbcConstants.BANK_CODE, msg.getBankCode());
		// 客户的归属编码
		requestParaMap.put(IcbcConstants.GROUP_CIS, msg.getCis());
		// 客户的证书ID（无证书客户可空)
		requestParaMap.put(IcbcConstants.ID, msg.getId());
		// 客户的指令包序列号（由客户ERP系统产生，不可重复)
		requestParaMap.put(IcbcConstants.PACKAGE_ID, msg.getfSeqno());
		// 客户的证书公钥信息（进行BASE64编码；NC客户送空)
		requestParaMap.put(IcbcConstants.CERT, "");
		// 客户的xml请求数据,由相应的Formatter生成
		requestParaMap.put(IcbcConstants.REQ_DATA, reqData);
		return requestParaMap;
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6050);
		}
	}

	public String getTransCode() {
		return transCode;
	}

	public void setTransCode(String transCode) {
		this.transCode = transCode;
	}

	public String getCis() {
		return cis;
	}

	public void setCis(String cis) {
		this.cis = cis;
	}

	public String getBankCode() {
		return bankCode;
	}

	public void setBankCode(String bankCode) {
		this.bankCode = bankCode;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getShopAcct() {
		return shopAcct;
	}

	public void setShopAcct(String shopAcct) {
		this.shopAcct = shopAcct;
	}

	public String getVersion() {
		return version;
	}

	public void setVersion(String version) {
		this.version = version;
	}
	
	
}
